package com.sensetime.jv.annotation;

import com.sensetime.jv.entity.UrlPermissionDTO;
import com.sensetime.jv.service.WhiteUrlCacheService;
import com.sensetime.jv.util.JsonUtils;
import com.sensetime.jv.vo.request.WhiteUrlRequestVO;
import jakarta.annotation.PostConstruct;
import lombok.Getter;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

@Component
public class PermissionScannerRunner {

    private final PermissionSyncHelper helper;
    private final RequestMappingHandlerMapping handlerMapping;
    private final WhiteUrlCacheService whiteUrlCacheService;

    @Value("${server.servlet.context-path}")
    private String servletPath;

    /* 对外暴露白名单 */
    @Getter
    private final List<String> whiteUrlList = new ArrayList<>();

    public PermissionScannerRunner(PermissionSyncHelper helper,
                                   @Qualifier("requestMappingHandlerMapping") RequestMappingHandlerMapping handlerMapping,
                                   WhiteUrlCacheService whiteUrlCacheService) {
        this.helper = helper;
        this.handlerMapping = handlerMapping;
        this.whiteUrlCacheService = whiteUrlCacheService;
    }

    @PostConstruct
    public void run() {
        List<UrlPermissionDTO> permissions = new ArrayList<>();
        List<UrlPermissionDTO> whiteUrls   = new ArrayList<>();

        handlerMapping.getHandlerMethods().forEach((info, hm) -> {
            RequirePermission rp = AnnotationUtils.findAnnotation(hm.getMethod(), RequirePermission.class);

            Set<String> urls = info.getPathPatternsCondition().getPatternValues();
            Set<String> methods = info.getMethodsCondition().getMethods().isEmpty()
                    ? Set.of(HttpMethod.GET.name())
                    : info.getMethodsCondition().getMethods()
                    .stream().map(Enum::name).collect(Collectors.toSet());

            for (String url : urls) {
                for (String method : methods) {
                    UrlPermissionDTO dto = new UrlPermissionDTO();
                    dto.setUrl(url);
                    dto.setMethod(method);
                    dto.setServletPath(servletPath);
                    dto.setDescription(rp == null ? "" : rp.description());

                    if (rp == null || rp.whiteUrl()) {
                        whiteUrlList.add(url);
                        whiteUrls.add(dto);
                    } else {
                        if (helper.shouldSkip(url, method, servletPath)) continue;
                        permissions.add(dto);
                    }
                }
            }
        });

        if (!whiteUrls.isEmpty()) {
            whiteUrlCacheService.cacheWhiteUrls(
                    whiteUrls.stream()
                            .map(d -> JsonUtils.objectMapper.convertValue(d, WhiteUrlRequestVO.class))
                            .collect(Collectors.toList()));
        }
        if (!permissions.isEmpty()) {
            helper.syncPermissionsBatchLock(permissions);
        }
    }
}